package ai.people.platform.oss.config;

import ai.people.platform.oss.properties.AliOssProperties;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSEncryptionClient;
import com.aliyun.oss.OSSEncryptionClientBuilder;
import com.aliyun.oss.crypto.SimpleRSAEncryptionMaterials;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;

import java.security.KeyPair;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.Map;

/**
 * oss工厂bean
 *
 * @author yuanqinglong
 * @date 2022/4/27 18:43
 */
@Component
@RequiredArgsConstructor
public class OssClientFactoryBean implements FactoryBean<OSS> {

    private final Logger logger = LoggerFactory.getLogger(OssClientFactoryBean.class);

    /**
     * 阿里oss客户属性
     */
    private final AliOssProperties aliOssProperties;

    /**
     * 创建加密OSSClient
     *
     * @return {@link OSS}
     * @throws Exception 异常
     */
    @Override
    public OSS getObject() throws Exception {
        // 您可以使用以下命令分别生成私钥与公钥pem文件，然后复制pem文件中的字符串到PRIVATE_PKCS1_PEM，PUBLIC_X509_PEM变量中。
        // openssl genrsa -out private_key.pem 2048
        // openssl rsa -in private_key.pem -out rsa_public_key.pem -pubout
        // 填写您的RSA私钥字符串，可以使用OpenSSL工具生成。以下为RSA私钥字符串的示例值。
        // 创建一个RSA密钥对。
        RSAPrivateKey privateKey = SimpleRSAEncryptionMaterials.getPrivateKeyFromPemPKCS1(aliOssProperties.getOssPrivateKey());
        RSAPublicKey publicKey = SimpleRSAEncryptionMaterials.getPublicKeyFromPemX509(aliOssProperties.getOssPublicKey());
        KeyPair keyPair = new KeyPair(publicKey, privateKey);
        // 创建主密钥RSA的描述信息，创建后不允许修改。主密钥描述信息和主密钥一一对应。
        // 如果所有的Object都使用相同的主密钥，主密钥描述信息可以为空，但后续不支持更换主密钥。
        // 如果主密钥描述信息为空，解密时无法判断文件使用的是哪个主密钥进行加密。
        // 强烈建议为每个主密钥都配置描述信息，由客户端保存主密钥和描述信息之间的对应关系（服务端不保存两者之间的对应关系）。
        Map<String, String> matDesc = new HashMap<>();
        matDesc.put("desc-key", "desc-value");

        // 创建RSA加密材料。
        SimpleRSAEncryptionMaterials encryptionMaterials = new SimpleRSAEncryptionMaterials(keyPair, matDesc);
        // 如果要下载并解密其他RSA密钥加密的文件，请将其他主密钥及其描述信息添加到加密材料中。
        // encryptionMaterials.addKeyPairDescMaterial(<otherKeyPair>, <otherKeyPairMatDesc>);
        // 创建RSA加密客户端。
        OSSEncryptionClient ossEncryptionClient = new OSSEncryptionClientBuilder().
                build(aliOssProperties.getEndpoint(), aliOssProperties.getAccessKeyId(),aliOssProperties.getAccessKeySecret(), encryptionMaterials);
        logger.info("OssClientFactoryBean create client complete {}", ossEncryptionClient);
        OssClientContextHolder.setRequestThreadHolder(ossEncryptionClient);
        return ossEncryptionClient;
    }


    /**
     * 返回OSS类型
     *
     * @return {@link Class}<{@link ?}>
     */
    @Override
    public Class<?> getObjectType() {
        return OSS.class;
    }


    /**
     * 创建对象为原型Bean
     *
     * @return boolean
     */
    @Override
    public boolean isSingleton() {
        return false;
    }
}
